require "./mme.rb"
require "./sgw.rb"
require "./pool.rb"

def input
  $stdin = File.open("config.txt")
  $stdin.each("\n") do |line|

    unless line[0]==35
    line =  line.split
    case line[0]

      #specify the constant bit rate
      when "cbr"
        $cbr=line[1].to_f

      when "pool"
        #create a new pool
        pool = Pool.new(line[1].to_i)

        #create MMEs and add them to pool
        #by default, each MME has a weight of 1
        (1+line.find_index("mme")...line.find_index("sgw")).each { |i| pool.add_mme(MME.new(1,line[i].to_i)) }

        #create SGWs and add them to pool
        (1+line.find_index("sgw")...line.size).each { |i| pool.add_sgw(SGW.new(pool.id,line[i].to_i)) }
        
        #add pool to the pools collection
        $pools.push(pool)

      when "time"
            $load.push(line[2..-1].map{|elem|elem.to_i } )
            $timeslots.push(line[1].to_i)
      else
    end
  end
end
end

$pools, $load, $timeslots = Array.new(), Array.new(), Array.new

input

t=0

#for each time slot
$load.each do |area_users|

  puts "\nTimeslot #{$timeslots[t]}\n"
  t+=1

  #in the beginning, each MME and each SGW has 0 users
  $pools.each do |pool|
    pool.mmes.each {|mme| mme.users = 0}
    pool.sgws.each {|sgw| sgw.users = 0}
  end

  #===========================================#
  #Distribution of users between MMEs and SGWs#
  #===========================================#
  $pools.each do |pool|
    pool.distribute_mme_users(area_users[$pools.find_index(pool)])
    pool.distribute_sgw_users(area_users[$pools.find_index(pool)])
  end

  $pools.each {|pool| pool.set_overload }

  #=======Here goes the magic=======#
  puts area_users
  
  $pools.each do |pool|

    #==================================#
    #MME load balancing inside the pool#
    #==================================#

    puts "\nStarting MME load balancing inside pool #{pool.id}\n"
    
    overloaded_mmes = Array.new()
    pool.mmes.each do |mme|
      if mme.overload_by_users>0
        overloaded_mmes.push(mme)
      end
    end

    unless overloaded_mmes.empty?
      overloaded_mmes.each do |source_mme|
        pool.mmes.each do |target_mme|
          unless ((overloaded_mmes.include?(target_mme)) || (target_mme.overload_by_users==0))
            pool.mmes[pool.mmes.find_index(source_mme)].handover($pools.find_index(pool),$pools.find_index(pool),pool.mmes.find_index(target_mme))
            if source_mme.overload_by_users<=0
              break
            end
          end
        end
      end
    end

    #==================================#
    #SGW load balancing inside the pool#
    #==================================#

    puts "\nStarting SGW load balancing inside pool #{pool.id}\n"

    overloaded_sgws = Array.new()
    pool.sgws.each do |sgw|
      if ((sgw.overload_by_users>0) || (sgw.overload_by_traffic>0))
        overloaded_sgws.push(sgw)
      end
    end

    unless overloaded_sgws.empty?
      overloaded_sgws.each do |source_sgw|
        pool.sgws.each do |target_sgw|
          unless ((overloaded_sgws.include?(target_sgw)) || (target_sgw.overload_by_users==0) || (target_sgw.overload_by_traffic==0))
            pool.sgws[pool.sgws.find_index(source_sgw)].handover($pools.find_index(pool),$pools.find_index(pool),pool.sgws.find_index(target_sgw))
            if (source_sgw.overload_by_users<=0 && source_sgw.overload_by_traffic<=0)
              break
            end
          end
        end
      end
    end
  end

  (0...$pools.size).each do |i|

    #==========================#
    #MME handover between pools#
    #==========================#
    
    puts "\nStarting MME handover for pool #{$pools[i].id}\n"

    #dealing with MMEs
    #if a pool is overloaded
    while $pools[i].mme_users_overload>0
      #find all pools which are not
      target_pools=$pools.find_all{ |pool| !(pool.overloaded_by_mme_users?) }
      #if we found some
      unless target_pools.empty?
        #select the least loaded one
        target_pool_index = $pools.find_index { |pool| pool.id == (target_pools.min_by{ |pool| pool.mmes_user_load_percentage }.id) }
        free_mme_index = $pools[target_pool_index].mmes.find_index($pools[target_pool_index].mmes.min_by { |mme| mme.users })
        #find the most loaded one and do the handover
        $pools[i].mmes[$pools[i].mmes.find_index($pools[i].mmes.max_by{ |mme| mme.users})].handover(i,target_pool_index,free_mme_index)
      else
        break
      end
    end

    string = "MMEs in pool #{$pools[i].id}: "
    $pools[i].mmes.each {|mme|string=string+mme.id.to_s+" "}
    puts string+"\n"
    string = "Users in each MME: \n"
    sum = 0
    $pools[i].mmes.each do |mme|
      string=string+mme.users.to_s+" "
      sum+=mme.users
    end
    string=string+"\nTotal users in MMEs: "+sum.to_s
    puts string+"\n"

    #==========================#
    #SGW handover between pools#
    #==========================#

    puts "\nStarting SGW handover for pool #{$pools[i].id}\n"

    #dealing with SGWs
    #if a pool is overloaded
    while (($pools[i].sgw_users_overload>0) || ($pools[i].sgw_traffic_overload > 0))
      #find all pools which are not
      target_pools=$pools.find_all{ |pool| (!pool.overloaded_by_sgw_users?) && (!pool.overloaded_by_sgw_traffic?) }
      #if we found some
      if target_pools.empty?
        break
      else
        #select the one which has the least traffic
        target_pool_index = $pools.find_index { |pool| pool.id == (target_pools.min_by{ |pool| pool.sgws_traffic_load_percentage }.id) }
        free_sgw_index = $pools[target_pool_index].sgws.find_index($pools[target_pool_index].sgws.min_by { |sgw| sgw.traffic })
        $pools[i].sgws[$pools[i].sgws.find_index($pools[i].sgws.max_by{ |sgw| sgw.traffic })].handover(i,target_pool_index,free_sgw_index)
      end
    end

  string = "SGWs in pool #{$pools[i].id}: "
  $pools[i].sgws.each {|sgw|string=string+sgw.id.to_s+" "}
  puts string+"\n"
  string = "Users in each SGW: \n"
  sum = 0
  $pools[i].sgws.each do |sgw|
    string=string+sgw.users.to_s+" "
    sum+=sgw.users
  end
  string=string+"\nTotal users in SGWs: "+sum.to_s
  puts string+"\n"

  end

  #================================#
  #MME and SGW exclusion from pools#
  #================================#

  puts "\nStarting MME and SGW exclusion\n"
  #now check if we can exclude MMEs and SGWs from multiple pools

  #select all MMEs that are included into multiple pools
  multiple_pools_mmes = Array.new()
  $pools.each do |pool|
    pool.mmes.each do |mme|
      if ((mme.pools.size>1) && (!multiple_pools_mmes.include?(mme)))
        multiple_pools_mmes.push(mme)
      end
    end
  end

  multiple_pools_mmes.each do |mme|
    mpools = mme.pools.reverse
    mpools.each do |current_pool|
      if (mme.pools.size>1) && (current_pool!=mme.pools[0])
        if $pools.find {|elem|elem.id==current_pool}.mme_exclude_possible?(mme)
          $pools.find{|elem|elem.id==current_pool}.mme_exclude(mme)
        end
      end
    end
  end

  #output
  $pools.each do |pool|
    string = "\nMMEs in pool #{pool.id}: "
    pool.mmes.each {|mme|string=string+mme.id.to_s+" "}
    puts string+"\n"
    string = "Users in each MME: \n"
    sum = 0
    pool.mmes.each do |mme|
      string=string+mme.users.to_s+" "
      sum+=mme.users
    end
    string=string+"\nTotal users in MMEs: "+sum.to_s
    puts string+"\n"
  end

  #select all SGWs that are included into multiple pools
  multiple_pools_sgws = Array.new()
  $pools.each do |pool|
    pool.sgws.each do |sgw|
      if ((sgw.pools.size>1) && (!multiple_pools_sgws.include?(sgw)))
        multiple_pools_sgws.push(sgw)
      end
    end
  end

  multiple_pools_sgws.each do |sgw|
    mpools = sgw.pools.reverse
    mpools.each do |current_pool|
      if ((sgw.pools.size>1) && (current_pool!=sgw.pools[0]))
        if $pools.find {|elem|elem.id==current_pool}.sgw_exclude_possible?(sgw)
          $pools.find{|elem|elem.id==current_pool}.sgw_exclude(sgw)
        end
      end
    end
  end

  #output
  $pools.each do |pool|
    string = "\nSGWs in pool #{pool.id}: "
    pool.sgws.each {|sgw|string=string+sgw.id.to_s+" "}
    puts string+"\n"
    string = "Users in each SGW: \n"
    sum = 0
    pool.sgws.each do |sgw|
      string=string+sgw.users.to_s+" "
      sum+=sgw.users
    end
    string=string+"\nTotal users in SGWs: "+sum.to_s
    puts string+"\n"
  end

end